package com.scs.application.modules.finance.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.service.DeptService;
import com.scs.application.modules.base.service.MatrService;
import com.scs.application.modules.base.service.SupplierService;
import com.scs.application.modules.finance.entity.BillItem;
import com.scs.application.modules.finance.entity.Invoice;
import com.scs.application.modules.finance.entity.InvoiceItem;
import com.scs.application.modules.finance.mapper.InvoiceMapper;
import com.scs.application.modules.finance.service.BillItemService;
import com.scs.application.modules.finance.service.InvoiceItemService;
import com.scs.application.modules.finance.service.InvoiceService;
import com.scs.application.modules.sys.entity.ScheduleJob;
import com.scs.application.modules.sys.mapper.ScheduleJobMapper;
import com.scs.application.modules.sys.service.ScheduleJobService;
import com.scs.application.modules.thirdparty.dto.InvoiceDTO;
import com.scs.application.modules.thirdparty.dto.InvoiceSyncDTO;
import com.scs.application.modules.thirdparty.service.MscmService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 开票单 服务实现类
 * </p>
 */
@Service
@Slf4j
public class InvoiceServiceImpl extends BaseServiceImpl<InvoiceMapper, Invoice> implements InvoiceService {

    @Autowired
    private MscmService mscmService;

    @Autowired
    private MatrService matrService;

    @Autowired
    @Lazy
    private ScheduleJobService scheduleJobService;

    @Autowired
    private InvoiceItemService invoiceItemService;

    @Autowired
    private SupplierService supplierService;

    @Autowired
    private DeptService deptService;

    @Resource
    private BillItemService billItemService;

    private final String INVOICE_SYNC_STATUS_YES = "1";

    private final String INVOICE_SYNC_STATUS_NO = "0";

    private final int UPDATE_INVOICE_ITEMS_LIMIT = 500; //明细每次更新条数

    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        List<InvoiceItem> invoiceItemList = invoiceItemService.list(new QueryWrapper<InvoiceItem>().select("id").in("invoice_id", idList));
        if (invoiceItemList.size() > 0) {
            invoiceItemService.removeCascadeByIds(invoiceItemList.stream().map(o -> o.getId()).collect(Collectors.toList()));
        }

        //通知未同步
        Collection<Invoice> invoices = this.listByIds(idList);
        List<InvoiceSyncDTO> invoiceSyncDTOS = Lists.newArrayListWithCapacity(idList.size());
        invoices.forEach(invoice -> {
            InvoiceSyncDTO invoiceSyncDTO = new InvoiceSyncDTO();
            invoiceSyncDTO.setId(invoice.getRefId()).setSyncStatus(INVOICE_SYNC_STATUS_NO);
            invoiceSyncDTOS.add(invoiceSyncDTO);
        });
        mscmService.syncInvoices(invoiceSyncDTOS);

        return this.removeByIds(idList);
    }

    /**
     * 从MSCM平台获取发票信息
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public String getInvoicesFromMSCM() {

        Date beginDate = DateUtils.parse(scheduleJobService.getLastSuccessDate("invoiceServiceImpl.getInvoicesFromMSCM()"));
        List<InvoiceDTO> invoiceDTOS = mscmService.getInvoices(beginDate);

        if (invoiceDTOS == null || invoiceDTOS.isEmpty()) {
            log.info("从MSCM系统中获取到{}张发票", "0");
            return StrUtil.format("从MSCM系统中获取到0张发票");
        }
        log.info("从MSCM系统中获取到{}张发票", invoiceDTOS.size());

        List<Invoice> invoices = Lists.newArrayListWithCapacity(invoiceDTOS.size());

        List<InvoiceItem> invoiceItems = Lists.newArrayList();
        List<InvoiceItem> dataInvoiceItems = invoiceItemService.list();
        List<Dept> depts = deptService.list();
        List<Invoice> dataInvoices = super.list(Wrappers.<Invoice>query().eq("flow_status", GlobalConsts.FLOW_START_VALUE));
        invoiceDTOS.forEach(invoiceDTO -> {
            Invoice invoice = new Invoice();
            BeanUtils.copyProperties(invoiceDTO, invoice);
            invoice.setRefId(invoiceDTO.getId());
            //判断是否存在，不存在的置id = null
            Optional<Invoice> optDataInvoice = dataInvoices.stream().filter(invoice1 -> invoice1.getRefId().equals(invoice.getRefId())).findFirst();
            if (!optDataInvoice.isPresent()) {
                invoice.setId(null);
            } else {
                invoice.setId(optDataInvoice.get().getId());
            }
            invoices.add(invoice);

            if (invoiceDTO.getItems().size() > 0) {
                invoiceItems.addAll(
                        invoiceDTO.getItems().stream().map(invoiceItemDTO -> {
                            InvoiceItem invoiceItem = new InvoiceItem();
                            BeanUtils.copyProperties(invoiceItemDTO, invoiceItem);
                            invoiceItem.setRefId(invoiceItem.getId());
                            //判断是否存在，不存在的置id = null
                            Optional<InvoiceItem> optInvoiceItem = dataInvoiceItems.stream().filter(item -> item.getRefId().equals(invoiceItem.getRefId())).findFirst();
                            if (!optInvoiceItem.isPresent()) {
                                invoiceItem.setId(null);
                            } else {
                                invoiceItem.setId(optInvoiceItem.get().getId());
                            }
                            return invoiceItem;
                        }).collect(Collectors.toList())
                );
            }
        });

        List<Supplier> suppliers = supplierService.list();
        //修正supplierId
        invoices.stream().forEach(invoice -> {
           Supplier sp = suppliers.stream().filter(supplier -> invoice.getSupplierId().equals(supplier.getMscmCode())).findFirst().orElse(null);
           if (sp != null) {
               invoice.setSupplierId(sp.getId());
           } else {
               invoice.setSupplierId("");
           }
        });

        List<Invoice> saveOrUpdateInvoices = invoices.stream().filter(invoice -> StringUtils.isNotEmpty(invoice.getSupplierId())).collect(Collectors.toList());
        super.saveOrUpdateBatch(saveOrUpdateInvoices); //只更新能匹配上供应商的数据

        for(int i = 0, j = 0; i < invoiceItems.size(); i += UPDATE_INVOICE_ITEMS_LIMIT, j++) { //每次更新500条明细
            List<InvoiceItem> saveOrUpdateInvoiceItems = invoiceItems.stream().skip(UPDATE_INVOICE_ITEMS_LIMIT * j).limit(UPDATE_INVOICE_ITEMS_LIMIT).collect(Collectors.toList());
            List<String> matrIds = billItemService.list(Wrappers.<BillItem>query().select("id", "matr_id").in("id", saveOrUpdateInvoiceItems.stream().map(InvoiceItem::getSourceKey).collect(Collectors.toList())))
                    .stream().map(BillItem::getMatrId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(matrIds)) { continue; }
            List<Matr> matrs = matrService.list(new QueryWrapper<Matr>().select("id", "mscm_code").in("id", matrIds));
            saveOrUpdateInvoiceItems.forEach(invoiceItem -> {
                if (matrs.size() > 0) {//批量更新matrid
                    matrs.stream().filter(mr -> invoiceItem.getMscmCode() != null && invoiceItem.getMscmCode().equalsIgnoreCase(mr.getMscmCode())).findAny().ifPresent(matr -> invoiceItem.setMatrId(matr.getId()));
                }
                saveOrUpdateInvoices.stream().filter(ic -> invoiceItem.getInvoiceId().equalsIgnoreCase(ic.getRefId())).findAny().ifPresent(invoice -> invoiceItem.setInvoiceId(invoice.getId()));//批量更新InvoiceId
                depts.stream().filter(dept -> invoiceItem.getDeptCode().equalsIgnoreCase(dept.getOfficeSystemCode())).findAny().ifPresent(dept -> invoiceItem.setDeptId(dept.getId()));
            });
            invoiceItemService.saveOrUpdateBatch(saveOrUpdateInvoiceItems);
        }

        //通知已同步
        List<InvoiceSyncDTO> invoiceSyncDTOS = Lists.newArrayListWithCapacity(saveOrUpdateInvoices.size());
        saveOrUpdateInvoices.forEach(invoice -> {
            InvoiceSyncDTO invoiceSyncDTO = new InvoiceSyncDTO();
            invoiceSyncDTO.setId(invoice.getRefId()).setSyncStatus(INVOICE_SYNC_STATUS_YES);
            invoiceSyncDTOS.add(invoiceSyncDTO);
        });
        mscmService.syncInvoices(invoiceSyncDTOS);

        return StrUtil.format("从MSCM系统中获取到{}张发票",saveOrUpdateInvoices.size());
    }
}
